package com.liaoyifan.core.opera;

import com.liaoyifan.core.annotation.TagOrder;
import com.liaoyifan.core.valid.Lang;
import io.swagger.v3.core.util.AnnotationsUtils;
import io.swagger.v3.oas.models.OpenAPI;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.providers.JavadocProvider;
import org.springdoc.core.service.SecurityService;
import org.springdoc.core.utils.PropertyResolverUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;

@SuppressWarnings("unused")
public class OpenApiService extends org.springdoc.core.service.OpenAPIService {

    public static final String ORDER = "x-order";

    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
    public OpenApiService(
            Optional<OpenAPI> openAPI,
            SecurityService securityParser,
            SpringDocConfigProperties springDocConfigProperties,
            PropertyResolverUtils propertyResolverUtils,
            Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers,
            Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers,
            Optional<JavadocProvider> javadocProvider) {
        super(
                openAPI,
                securityParser,
                springDocConfigProperties,
                propertyResolverUtils,
                openApiBuilderCustomizers,
                serverBaseUrlCustomizers,
                javadocProvider);
    }

    @Override
    public void buildTagsFromClass(
            Class<?> beanType,
            Set<io.swagger.v3.oas.models.tags.Tag> tags,
            Set<String> tagsStr,
            Locale locale) {
        Set<io.swagger.v3.oas.annotations.tags.Tag> tagAnnotations =
                AnnotatedElementUtils.findAllMergedAnnotations(
                                beanType, io.swagger.v3.oas.annotations.tags.Tags.class)
                        .stream()
                        .flatMap((x) -> Stream.of(x.value()))
                        .collect(Collectors.toSet());
        tagAnnotations.addAll(
                AnnotatedElementUtils.findAllMergedAnnotations(
                        beanType, io.swagger.v3.oas.annotations.tags.Tag.class));
        if (Lang.isNotEmpty(tagAnnotations)) {
            tagsStr.addAll(
                    tagAnnotations.stream()
                            .map(io.swagger.v3.oas.annotations.tags.Tag::name)
                            .collect(Collectors.toSet()));
            this.addTags(beanType, tagAnnotations, tags);
        }
    }

    private void addTags(
            Class<?> beanType,
            Set<io.swagger.v3.oas.annotations.tags.Tag> tagAnnotations,
            Set<io.swagger.v3.oas.models.tags.Tag> tags) {
        Optional<Set<io.swagger.v3.oas.models.tags.Tag>> optional =
                AnnotationsUtils.getTags(
                        tagAnnotations.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]),
                        false);
        TagOrder order = AnnotationUtils.findAnnotation(beanType, TagOrder.class);
        optional.ifPresent(
                i ->
                        i.forEach(
                                tag -> {
                                    tag.name(tag.getName());
                                    tag.description(tag.getDescription());
                                    if (tags.stream()
                                            .noneMatch(t -> t.getName().equals(tag.getName()))) {
                                        tag.addExtension(
                                                ORDER,
                                                order != null ? order.value() : Integer.MAX_VALUE);
                                        tags.add(tag);
                                    }
                                }));
    }
}
